﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.Configuration
Imports System.Globalization
Imports System.Reflection
Imports System.Threading
Imports System.Workflow.Runtime.Configuration
Imports System.Workflow.Runtime.Hosting

Namespace System.Workflow.Activities
    Public Class ExternalDataExchangeService
        Inherits WorkflowRuntimeService
        ' Methods
        Public Sub New()
            Me.sync = New Object
            Me.eventHandlers = New Dictionary([Of] Integer, WorkflowMessageEventHandler)
        End Sub

        Public Sub New(ByVal parameters As NameValueCollection)
            Me.New()
            If (parameters Is Nothing) Then
                Throw New ArgumentNullException("parameters")
            End If
            Dim sectionName As String = Nothing
            Dim str2 As String
            For Each str2 In parameters.Keys
                If Not str2.Equals("ConfigurationSection", StringComparison.OrdinalIgnoreCase) Then
                    Throw New ArgumentException(String.Format(Thread.CurrentThread.CurrentCulture, SR.GetString("Error_UnknownConfigurationParameter"), New Object() { str2 }), "parameters")
                End If
                sectionName = parameters.Item(str2)
            Next
            If (Not sectionName Is Nothing) Then
                Me.settings = [TryCast](ConfigurationManager.GetSection(sectionName),ExternalDataExchangeServiceSection)
                If (Me.settings Is Nothing) Then
                    Throw New ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ConfigurationSectionNotFound"), New Object() { sectionName }))
                End If
            End If
        End Sub

        Public Sub New(ByVal configSectionName As String)
            Me.New()
            If (configSectionName Is Nothing) Then
                Throw New ArgumentNullException("configSectionName")
            End If
            Me.settings = [TryCast](ConfigurationManager.GetSection(configSectionName),ExternalDataExchangeServiceSection)
            If (Me.settings Is Nothing) Then
                Throw New ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ConfigurationSectionNotFound"), New Object() { configSectionName }))
            End If
        End Sub

        Public Sub New(ByVal settings As ExternalDataExchangeServiceSection)
            Me.New()
            If (settings Is Nothing) Then
                Throw New ArgumentNullException("settings")
            End If
            Me.settings = settings
        End Sub

        Private Sub AddRemove(ByVal addedservice As Object, ByVal delg As Delegate, ByVal add As Boolean, ByVal eventName As String)
            Try 
                Dim str As String
                If add Then
                    str = ("add_" & eventName)
                Else
                    str = ("remove_" & eventName)
                End If
                Dim type As Type = addedservice.GetType
                If (Not delg Is Nothing) Then
                    Dim args As Object() = New Object() { delg }
                    type.InvokeMember(str, BindingFlags.InvokeMethod, Nothing, addedservice, args, Nothing)
                End If
            Catch exception As Exception
                If ExternalDataExchangeService.IsIrrecoverableException(exception) Then
                    Throw
                End If
            End Try
        End Sub

        Public Sub AddService(ByVal service As Object)
            If (service Is Nothing) Then
                Throw New ArgumentNullException("service")
            End If
            If (MyBase.Runtime Is Nothing) Then
                Throw New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ExternalRuntimeContainerNotFound"), New Object(0  - 1) {}))
            End If
            Me.InterceptService(service, True)
            MyBase.Runtime.AddService(service)
        End Sub

        Public Function GetService(ByVal serviceType As Type) As Object
            If (serviceType Is Nothing) Then
                Throw New ArgumentNullException("serviceType")
            End If
            If (MyBase.Runtime Is Nothing) Then
                Throw New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ExternalRuntimeContainerNotFound"), New Object(0  - 1) {}))
            End If
            Return MyBase.Runtime.GetService(serviceType)
        End Function

        Private Sub InterceptService(ByVal service As Object, ByVal add As Boolean)
            Dim flag As Boolean = False
            Dim type As Type
            For Each type In service.GetType.GetInterfaces
                If (type.GetCustomAttributes(GetType(ExternalDataExchangeAttribute), False).Length <> 0) Then
                    If ((Not MyBase.Runtime.GetService(type) Is Nothing) AndAlso add) Then
                        Throw New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ExternalDataExchangeServiceExists"), New Object() { type }))
                    End If
                    flag = True
                    Dim events As EventInfo() = type.GetEvents
                    If (Not events Is Nothing) Then
                        Dim info As EventInfo
                        For Each info In events
                            Dim handler As WorkflowMessageEventHandler = Nothing
                            Dim key As Integer = (type.GetHashCode Xor info.Name.GetHashCode)
                            SyncLock Me.sync
                                If Not Me.eventHandlers.ContainsKey(key) Then
                                    handler = New WorkflowMessageEventHandler(type, info, MyBase.Runtime)
                                    Me.eventHandlers.Add(key, handler)
                                Else
                                    handler = Me.eventHandlers.Item(key)
                                End If
                            End SyncLock
                            Me.AddRemove(service, handler.Delegate, add, info.Name)
                        Next
                    End If
                End If
            Next
            If Not flag Then
                Throw New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ServiceMissingExternalDataExchangeInterface"), New Object(0  - 1) {}))
            End If
        End Sub

        Friend Shared Function IsIrrecoverableException(ByVal e As Exception) As Boolean
            Return (((TypeOf e Is OutOfMemoryException OrElse TypeOf e Is ExecutionEngineException) OrElse (TypeOf e Is StackOverflowException OrElse TypeOf e Is ThreadInterruptedException)) OrElse TypeOf e Is ThreadAbortException)
        End Function

        Public Sub RemoveService(ByVal service As Object)
            If (service Is Nothing) Then
                Throw New ArgumentNullException("service")
            End If
            If (MyBase.Runtime Is Nothing) Then
                Throw New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_ExternalRuntimeContainerNotFound"), New Object(0  - 1) {}))
            End If
            Me.InterceptService(service, False)
            MyBase.Runtime.RemoveService(service)
        End Sub

        Private Function ServiceFromSettings(ByVal serviceSettings As WorkflowRuntimeServiceElement) As Object
            Dim type As Type = Type.GetType(serviceSettings.Type, True)
            Dim info As ConstructorInfo = Nothing
            Dim info2 As ConstructorInfo = Nothing
            Dim info3 As ConstructorInfo = Nothing
            Dim info4 As ConstructorInfo
            For Each info4 In type.GetConstructors
                Dim parameters As ParameterInfo() = info4.GetParameters
                If (parameters.Length = 1) Then
                    If GetType(IServiceProvider).IsAssignableFrom(parameters(0).ParameterType) Then
                        info2 = info4
                    ElseIf GetType(NameValueCollection).IsAssignableFrom(parameters(0).ParameterType) Then
                        info3 = info4
                    End If
                ElseIf (((parameters.Length = 2) AndAlso GetType(IServiceProvider).IsAssignableFrom(parameters(0).ParameterType)) AndAlso GetType(NameValueCollection).IsAssignableFrom(parameters(1).ParameterType)) Then
                    info = info4
                    Exit For
                End If
            Next
            If (Not info Is Nothing) Then
                Return info.Invoke(New Object() { MyBase.Runtime, serviceSettings.Parameters })
            End If
            If (Not info2 Is Nothing) Then
                Return info2.Invoke(New Object() { MyBase.Runtime })
            End If
            If (Not info3 Is Nothing) Then
                Return info3.Invoke(New Object() { serviceSettings.Parameters })
            End If
            Return Activator.CreateInstance(type)
        End Function

        Protected Overrides Sub Start()
            If (Not Me.settings Is Nothing) Then
                Dim element As WorkflowRuntimeServiceElement
                For Each element In Me.settings.Services
                    Me.AddService(Me.ServiceFromSettings(element))
                Next
            End If
            MyBase.Start
        End Sub


        ' Fields
        Private Const configurationSectionAttributeName As String = "ConfigurationSection"
        Private eventHandlers As Dictionary([Of] Integer, WorkflowMessageEventHandler)
        Private settings As ExternalDataExchangeServiceSection
        Private sync As Object
    End Class
End Namespace

